; 从cmos读取时间信息
; 时间信息在内存中的形式
; 序号  0      2        4         7       8       9
; 内容  秒     分       时       日      月       年
;
; 内容形式以BCD 码保存
; 例如  46 秒：
;        4      6
;       ||     ||
;       0100  0110   0
;   如何显示？
;   al:0100 0110
;   mov ah, al
;                  右移4位
;   ah:0100 0110  ========> 0000  0100 + 32H = (数字的ASCII码) 4 + 48 = 52
;                   与运算（0000 1111B）
;   al:0100 0110  ==================>      0100 0110
;                                     and  0000 1111
;                                      ——————————————————
;                                          (0000 0110 = 6) + 32H  = 54
; 如何读取cmoss数据？
;                       地址端口： 70H           
;     cmos 有两个端口                   共有128字节（0 ~ 127）
;                       数据端口: 71H
;     读写主要通过 al 和 ax
;   读取：先将地址编号放到地址端口
;            mov al, 2
;            out 70H, al
;         然后通过 71H 读取数据到al 或ax
;           in al, 71H
;
assume cs:code, ss: stack


stack segment stack

    db 32 dup(0)
stack ends

code segment

TIME_STYLE  db 'YY/MM/DD HH:II:SS', 0

TIME_INDEX  db 9, 8, 7, 4, 2, 0

start:

    mov ax, stack

    mov ss, ax

    mov sp, 32

    call initReg

    call clearScreen

    mov di, OFFSET TIME_INDEX

    mov si, OFFSET TIME_STYLE

    mov bp, 160 * 15 + 40   ; 显示位置

    call displayTimeStyle

    call displayTime

    mov ax, 4c00H

    int 21H

    ret

displayTimeStyle:

    push si

    push bp

loopStart:
    mov al, ds:[si]

    cmp al, 0

    je over

    mov es:[bp], al

    add si, 1

    add bp, 2

    jmp loopStart
   
over:
    pop bp
    pop si
    ret


; 移位 4 次
displacement:

    shr ah, 1
    shr ah, 1
    shr ah, 1
    shr ah, 1

    ret

; 显示分钟
displayTime:

reset:
    mov cx, 6

    push cx
    push di

    push bp

showTime:
    mov al, ds:[di]

    out 70H, al

    in al, 71H

    mov ah, al

    call displacement
    
    add ah, 30H

    and al, 00001111B

    add al, 30H

    mov es:[bp], ah

    mov byte ptr es:[bp + 1], 4

    mov es:[bp + 2], al

    mov  byte ptr es:[bp + 3], 4

    add bp, 6

    inc di

    loop showTime

    pop bp

    pop di

    pop cx

    jmp reset

    ret

clearScreen:

    mov cx, 2000
    mov di, 0
    mov bx, 0700H
clear:
    mov es:[di], bx

    add di, 2

    loop clear

    mov cx, 0

    mov bx, 0

    ret
initReg:

    mov ax, 0b800H

    mov es, ax

    mov ax, cs

    mov ds, ax

    mov ax, 0

    ret

code ends

end start